package com.superview.action;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Pattern;

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;

import org.springframework.stereotype.Component;

import com.superview.domain.DialogueCache;
import com.superview.domain.Items;
import com.superview.domain.PhonesImformation;
import com.superview.domain.TickParam;
import com.superview.domain.Unit;
import com.superview.util.PhoneRuntime;

import steed.hibernatemaster.util.DaoUtil;
import steed.util.base.BaseUtil;

/**
 * @ServerEndPoint 注解是一个类层次的注解，它的功能主要是将目前的类定义成一个websocket服务器端，
 *                 注解的值将被用于监听用户连接的终端访问URL地址，客户端可以通过这个URL连接到websocket服务器端
 */
@javax.websocket.server.ServerEndpoint("/websocket")
@Component
public class WebSockAction {
	private static int onlineCount = 0;
	public static CopyOnWriteArrayList<Session> sessions = new CopyOnWriteArrayList<Session>();

	// 音频保存根路径
	public static String wavRootPath = "";

	public WebSockAction() {
		System.out.println("有新连接加入！当前在线人数为" + getOnlineCount());
	}

	@OnOpen
	public void onOpen(Session session) {
		sessions.add(session);// 加入set中
		addOnlineCount();
		System.out.println("有新连接加入！当前链接数为" + getOnlineCount());
	}

	@OnClose
	public void onClose(Session session) {
		sessions.remove(session);
		subOnlineCount();
		System.out.println("有一连接关闭！当前链接数为" + getOnlineCount());
	}

	@OnMessage
	public void onMessage(String message, Session session) {
		BaseUtil.out(session.getId());
		System.out.println("来自客户端的消息：" + message);
////        群发消息
//        for (WebSockAction item:webSocketSet){
//            try {
//                item.sendMessage(message);
//            } catch (IOException e) {
//                e.printStackTrace();
//                continue;
//            }
//        }
		// 给另外其他session发消息
		for (Session item : sessions) {
//        	if (item.equals(session)) {
//				continue;
//			}
			sendParams(item, message);
		}

	}

	public static void sendParams(Session item, String message) {
		//去掉标点符号
		message = filterPoints(message);
		// 调用python程序获取句子所有的音素
//    	PinyinRuntime runtime = new PinyinRuntime();
//		String result = runtime.GetPinyin(message);
		String path = wavRootPath;
		String filename = "result.wav";

		PhoneRuntime runtime = new PhoneRuntime();
		//先从数据库里面找匹配的文本，如果数据库有，那么就直接返回数据库的，如果数据库没有，则进行计算缓存
		String result = getFromCache(message);
		if (result == null) {
			result = runtime.GetPhoneTimes(message);
			saveCache(message,result);
		}
//		String result = "{'xmin': '0.0', 'xmax': '8.6259375', 'size': 2, 'tiers': [{'idx': '1', 'name': 'words', 'xmin': '0.0', 'xmax': '8.6259375', 'size': '27', 'items': [{'idx': '1', 'xmin': '0.0', 'xmax': '0.480', 'text': ''}, {'idx': '2', 'xmin': '0.480', 'xmax': '0.560', 'text': 'ni3'}, {'idx': '3', 'xmin': '0.560', 'xmax': '0.750', 'text': ''}, {'idx': '4', 'xmin': '0.750', 'xmax': '1.200', 'text': 'hao3'}, {'idx': '5', 'xmin': '1.200', 'xmax': '1.660', 'text': ''}, {'idx': '6', 'xmin': '1.660', 'xmax': '1.960', 'text': 'wo3'}, {'idx': '7', 'xmin': '1.960', 'xmax': '2.060', 'text': 'shi4'}, {'idx': '8', 'xmin': '2.060', 'xmax': '2.320', 'text': ''}, {'idx': '9', 'xmin': '2.320', 'xmax': '2.730', 'text': 'chao1'}, {'idx': '10', 'xmin': '2.730', 'xmax': '2.870', 'text': ''}, {'idx': '11', 'xmin': '2.870', 'xmax': '3.070', 'text': 'wei2'}, {'idx': '12', 'xmin': '3.070', 'xmax': '3.360', 'text': 'shi4'}, {'idx': '13', 'xmin': '3.360', 'xmax': '3.680', 'text': 'jie4'}, {'idx': '14', 'xmin': '3.680', 'xmax': '3.990', 'text': 'lu4'}, {'idx': '15', 'xmin': '3.990', 'xmax': '4.790', 'text': 'xi1'}, {'idx': '16', 'xmin': '4.790', 'xmax': '4.820', 'text': 'wo3'}, {'idx': '17', 'xmin': '4.820', 'xmax': '5.270', 'text': ''}, {'idx': '18', 'xmin': '5.270', 'xmax': '5.350', 'text': 'jue2'}, {'idx': '19', 'xmin': '5.350', 'xmax': '5.930', 'text': ''}, {'idx': '20', 'xmin': '5.930', 'xmax': '6.050', 'text': 'de2'}, {'idx': '21', 'xmin': '6.050', 'xmax': '6.400', 'text': 'dong3'}, {'idx': '22', 'xmin': '6.400', 'xmax': '6.470', 'text': ''}, {'idx': '23', 'xmin': '6.470', 'xmax': '6.740', 'text': 'ge1'}, {'idx': '24', 'xmin': '6.740', 'xmax': '7.160', 'text': 'chao1'}, {'idx': '25', 'xmin': '7.160', 'xmax': '7.210', 'text': ''}, {'idx': '26', 'xmin': '7.210', 'xmax': '7.520', 'text': 'shuai4'}, {'idx': '27', 'xmin': '7.520', 'xmax': '8.6259375', 'text': ''}]}, {'idx': '2', 'name': 'phones', 'xmin': '0.0', 'xmax': '8.6259375', 'size': '43', 'items': [{'idx': '1', 'xmin': '0.000', 'xmax': '0.480', 'text': 'sil'}, {'idx': '2', 'xmin': '0.480', 'xmax': '0.530', 'text': 'n'}, {'idx': '3', 'xmin': '0.530', 'xmax': '0.560', 'text': 'i3'}, {'idx': '4', 'xmin': '0.560', 'xmax': '0.750', 'text': 'sp'}, {'idx': '5', 'xmin': '0.750', 'xmax': '0.920', 'text': 'h'}, {'idx': '6', 'xmin': '0.920', 'xmax': '1.200', 'text': 'ao3'}, {'idx': '7', 'xmin': '1.200', 'xmax': '1.660', 'text': 'sp'}, {'idx': '8', 'xmin': '1.660', 'xmax': '1.960', 'text': 'uo3'}, {'idx': '9', 'xmin': '1.960', 'xmax': '2.030', 'text': 'sh'}, {'idx': '10', 'xmin': '2.030', 'xmax': '2.060', 'text': 'ii4'}, {'idx': '11', 'xmin': '2.060', 'xmax': '2.320', 'text': 'sp'}, {'idx': '12', 'xmin': '2.320', 'xmax': '2.560', 'text': 'ch'}, {'idx': '13', 'xmin': '2.560', 'xmax': '2.730', 'text': 'ao1'}, {'idx': '14', 'xmin': '2.730', 'xmax': '2.870', 'text': 'sp'}, {'idx': '15', 'xmin': '2.870', 'xmax': '3.070', 'text': 'uei2'}, {'idx': '16', 'xmin': '3.070', 'xmax': '3.240', 'text': 'sh'}, {'idx': '17', 'xmin': '3.240', 'xmax': '3.360', 'text': 'ii4'}, {'idx': '18', 'xmin': '3.360', 'xmax': '3.510', 'text': 'j'}, {'idx': '19', 'xmin': '3.510', 'xmax': '3.680', 'text': 'ie4'}, {'idx': '20', 'xmin': '3.680', 'xmax': '3.810', 'text': 'l'}, {'idx': '21', 'xmin': '3.810', 'xmax': '3.990', 'text': 'u4'}, {'idx': '22', 'xmin': '3.990', 'xmax': '4.310', 'text': 'x'}, {'idx': '23', 'xmin': '4.310', 'xmax': '4.790', 'text': 'i1'}, {'idx': '24', 'xmin': '4.790', 'xmax': '4.820', 'text': 'uo3'}, {'idx': '25', 'xmin': '4.820', 'xmax': '5.270', 'text': 'sp'}, {'idx': '26', 'xmin': '5.270', 'xmax': '5.320', 'text': 'j'}, {'idx': '27', 'xmin': '5.320', 'xmax': '5.350', 'text': 've2'}, {'idx': '28', 'xmin': '5.350', 'xmax': '5.930', 'text': 'sp'}, {'idx': '29', 'xmin': '5.930', 'xmax': '5.960', 'text': 'd'}, {'idx': '30', 'xmin': '5.960', 'xmax': '6.050', 'text': 'e2'}, {'idx': '31', 'xmin': '6.050', 'xmax': '6.200', 'text': 'd'}, {'idx': '32', 'xmin': '6.200', 'xmax': '6.280', 'text': 'o3'}, {'idx': '33', 'xmin': '6.280', 'xmax': '6.400', 'text': 'ng'}, {'idx': '34', 'xmin': '6.400', 'xmax': '6.470', 'text': 'sp'}, {'idx': '35', 'xmin': '6.470', 'xmax': '6.550', 'text': 'g'}, {'idx': '36', 'xmin': '6.550', 'xmax': '6.740', 'text': 'e1'}, {'idx': '37', 'xmin': '6.740', 'xmax': '6.970', 'text': 'ch'}, {'idx': '38', 'xmin': '6.970', 'xmax': '7.160', 'text': 'ao1'}, {'idx': '39', 'xmin': '7.160', 'xmax': '7.210', 'text': 'sp'}, {'idx': '40', 'xmin': '7.210', 'xmax': '7.460', 'text': 'sh'}, {'idx': '41', 'xmin': '7.460', 'xmax': '7.520', 'text': 'uai4'}, {'idx': '42', 'xmin': '7.520', 'xmax': '8.610', 'text': 'sp'}, {'idx': '43', 'xmin': '8.610', 'xmax': '8.6259375', 'text': ''}]}], 'wave_path': 'C:\\\\develop\\\\git\\\\virtualhuman\\\\chaowei-speech-txt-align\\\\corpus\\\\chaowei.wav'}";
//		String result = "{'xmin': '0.0', 'xmax': '1.4453125', 'size': 2, 'tiers': [{'idx': '1', 'name': 'words', 'xmin': '0.0', 'xmax': '1.4453125', 'size': '7', 'items': [{'idx': '1', 'xmin': '0.000', 'xmax': '0.240', 'text': 'chao1'}, {'idx': '2', 'xmin': '0.240', 'xmax': '0.310', 'text': ''}, {'idx': '3', 'xmin': '0.310', 'xmax': '0.370', 'text': 'wei2'}, {'idx': '4', 'xmin': '0.370', 'xmax': '0.540', 'text': 'shi4'}, {'idx': '5', 'xmin': '0.540', 'xmax': '0.660', 'text': ''}, {'idx': '6', 'xmin': '0.660', 'xmax': '0.870', 'text': 'jie4'}, {'idx': '7', 'xmin': '0.870', 'xmax': '1.4453125', 'text': ''}]}, {'idx': '2', 'name': 'phones', 'xmin': '0.0', 'xmax': '1.4453125', 'size': '11', 'items': [{'idx': '1', 'xmin': '0.000', 'xmax': '0.110', 'text': 'ch'}, {'idx': '2', 'xmin': '0.110', 'xmax': '0.240', 'text': 'ao1'}, {'idx': '3', 'xmin': '0.240', 'xmax': '0.310', 'text': 'sp'}, {'idx': '4', 'xmin': '0.310', 'xmax': '0.370', 'text': 'uei2'}, {'idx': '5', 'xmin': '0.370', 'xmax': '0.500', 'text': 'sh'}, {'idx': '6', 'xmin': '0.500', 'xmax': '0.540', 'text': 'ii4'}, {'idx': '7', 'xmin': '0.540', 'xmax': '0.660', 'text': 'sp'}, {'idx': '8', 'xmin': '0.660', 'xmax': '0.710', 'text': 'j'}, {'idx': '9', 'xmin': '0.710', 'xmax': '0.870', 'text': 'ie4'}, {'idx': '10', 'xmin': '0.870', 'xmax': '1.430', 'text': 'sp'}, {'idx': '11', 'xmin': '1.430', 'xmax': '1.4453125', 'text': ''}]}], 'wave_path': 'C:/develop/git/virtualhuman/chaowei-speech-txt-align/corpus/chaowei.wav'}";
		System.out.println(result);
		PhonesImformation phonesImformation = BaseUtil.parseJson(result, PhonesImformation.class);
		if (phonesImformation == null) {
			return;
		}
		DownloadAction.setFileUri(phonesImformation.getWave_path());
		// 将声调过滤掉
		for (Items item2 : phonesImformation.getTiers().get(1).getItems()) {
			String text = item2.getText();
			String text2 = Pattern.compile("[\\d]").matcher(text).replaceAll("");
			item2.setText(text2);
		}
		try {
			sendMessage(item, BaseUtil.getJson(phonesImformation));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	//过滤标点符号
	private static String filterPoints(String message) {
		return message.replaceAll("[\\pP\\pS\\pZ]", "");
	}

	private static void saveCache(String message, String result) {
		// TODO Auto-generated method stub
		DialogueCache cache = new DialogueCache();
		cache.setText(message);
		cache.setPhoneSequence(result);
		cache.save();
	}

	private static String getFromCache(String message) {
		DialogueCache where = new DialogueCache();
		where.setText(message);
		DialogueCache cache = DaoUtil.listOne(where);
		if (cache !=null) {
			return cache.getPhoneSequence();
		}
		return null;
	}

	public static List<TickParam> getTickParams(int textLength, double peak) {
		List<TickParam> tickParams = new ArrayList<TickParam>();
		for (int i = 0; i < textLength; i++) {
			tickParams.addAll(createTickParam(1.0, peak));
//        	tickParams.addAll(createTickParam(0.24,peak));
//        	tickParams.addAll(createTickParam(0.4,peak));
//        	tickParams.addAll(createTickParam(0.8,peak));
		}
		return tickParams;
	}

	private static List<TickParam> createTickParam(double top, double magnitude) {
		if (magnitude == 0.0) {
			return null;
		}
		List<TickParam> tickParams = new ArrayList<TickParam>();
		for (int i = 0; i <= (int) magnitude; i++) {
			TickParam param = new TickParam();
			Unit unit = new Unit();
//			unit.setName("jaw_down");
			unit.setName("Bs_Eye_R");
			unit.setValue((double) (top / magnitude) * i);
			param.getUnits().add(unit);
			tickParams.add(param);
		}
		for (int i = (int) magnitude; i >= 0; i--) {
			TickParam param = new TickParam();
			Unit unit = new Unit();
			unit.setName("Bs_Eye_R");
			unit.setValue((double) (top / magnitude) * i);
			param.getUnits().add(unit);
			tickParams.add(param);
		}
		return tickParams;
	}

	public static double GetWavSeconds(String filePath) {
		File file = new File(filePath);
		Clip clip;
		try {
			clip = AudioSystem.getClip();
			AudioInputStream ais = AudioSystem.getAudioInputStream(file);
			clip.open(ais);
			System.out.println(clip.getMicrosecondLength() / 1000000D + " s");
			return clip.getMicrosecondLength() / 1000000D;
		} catch (LineUnavailableException e) {
			e.printStackTrace();
		} catch (UnsupportedAudioFileException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return 0.0;
	}

	private static int getTextLength(String message) {
		String str = (message.replaceAll("[^\\u4e00-\\u9fa5]", ""));
		return str.length();
	}

	@OnError
	public void onError(Session session, Throwable throwable) {
		System.out.println("发生错误！");
		throwable.printStackTrace();
	}

//   下面是自定义的一些方法
	public static void sendMessage(Session session, String message) throws IOException {
		session.getBasicRemote().sendText(message);
	}

	public static synchronized int getOnlineCount() {
		return onlineCount;
	}

	public static synchronized void addOnlineCount() {
		WebSockAction.onlineCount++;
	}

	public static synchronized void subOnlineCount() {
		WebSockAction.onlineCount--;
	}

	public static void sendEmotion(Session item, String emotionUri) {
		PhonesImformation phonesImformation = new PhonesImformation();
		phonesImformation.setMode(1);
		phonesImformation.setMotionUri(emotionUri);
		try {
			sendMessage(item, BaseUtil.getJson(phonesImformation));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
